<?php

$enableChartDirector = true;
if ($enableChartDirector) {
    Yii::import('application.vendors.*');
    require_once('ChartDirector/lib/financefunction.php');
}

class StockController extends Controller {

    /**
     * @var string the default layout for the views. Defaults to '//layouts/column2', meaning
     * using two-column layout. See 'protected/views/layouts/column2.php'.
     */
    public $layout = '//layouts/column2';

    /**
     * @return array action filters
     */
    public function filters() {
        return array(
            'accessControl', // perform access control for CRUD operations
        );
    }

    /**
     * Specifies the access control rules.
     * This method is used by the 'accessControl' filter.
     * @return array access control rules
     */
    public function accessRules() {
        $isAdmin = 'isset(Yii::app()->user->role) && (Yii::app()->user->role==="admin")';
        $isStaff = 'isset(Yii::app()->user->role) && (Yii::app()->user->role==="staff")';
        $isSubscriber = 'isset(Yii::app()->user->role) && (Yii::app()->user->role==="subscriber")';
        return array(
            //Public
            array(
                'allow', // Deny amonyous to do anything
                'actions' => array(
                    'chart', 'getChart', //Actions for Chart page
                    'formula', 'SLR',
                    'report',
                ),
                'users' => array('?'),
            ),
            //Authenticated/Logged-in users
            array(
                'allow',
                'actions' => array(
                    'chart', 'getChart', //Actions for Chart page
                    'formula', 'SLR',
                    'report',
                ),
                'users' => array('@'),
            ),
            //Staff
            array(
                'allow',
                'actions' => array(
                    'create', 'update', 'delete', //Default Yii actions
                    'index', 'addStock', 'edit', //Actions' used for inline-editor
                    'importFromFile', 'importFromWeb', //Import data from many source
                    'validation', 'dataValidate', 'UpdateAjax', //Actions for validate function 
                ),
                'expression' => $isStaff,
            ),
            //Admin users
            array(
                'allow',
                'actions' => array(
                    'create', 'update', 'delete', //Default Yii actions
                    'index', 'addStock', 'edit', //Actions' used for inline-editor
                    'importFromFile', 'importFromWeb', //Import data from many source
                    'validation', 'dataValidate', 'UpdateAjax', 'UpdateAjax', //Actions for validate function 
                ),
                'expression' => $isAdmin,
            ),
            array(
                'deny', // deny all users
                'users' => array('*'),
            ),
        );
    }

    /**
     * Displays a particular model.
     * @param integer $id the ID of the model to be displayed
     */
    public function actionView($id) {
        $this->render('view', array(
            'model' => $this->loadModel($id),
        ));
    }

    /**
     * Creates a new model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     */
    public function actionCreate() {
        $model = new Stock;

        // Uncomment the following line if AJAX validation is needed
        // $this->performAjaxValidation($model);

        if (isset($_POST['Stock'])) {
            $model->attributes = $_POST['Stock'];
            if ($model->save())
                $this->redirect(array('view', 'id' => $model->id));
        }

        $this->render('create', array(
            'model' => $model,
        ));
    }

    /**
     * Updates a particular model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param integer $id the ID of the model to be updated
     */
    public function actionUpdate($id) {
        $model = $this->loadModel($id);

        // Uncomment the following line if AJAX validation is needed
        // $this->performAjaxValidation($model);

        if (isset($_POST['Stock'])) {
            $model->attributes = $_POST['Stock'];
            if ($model->save())
                $this->redirect(array('view', 'id' => $model->id));
        }

        $this->render('update', array(
            'model' => $model,
        ));
    }

    /**
     * Deletes a particular model.
     * If deletion is successful, the browser will be redirected to the 'admin' page.
     * @param integer $id the ID of the model to be deleted
     */
    public function actionDelete($id) {
        if (Yii::app()->request->isPostRequest) {
            // we only allow deletion via POST request
            $this->loadModel($id)->delete();

            // if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
            if (!isset($_GET['ajax']))
                $this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));
        }
        else
            throw new CHttpException(400, 'Invalid request. Please do not repeat this request again.');
    }

    /**
     * Lists all models.
     */
    public function actionIndex() {
        $model = new Stock('search');
        $model->unsetAttributes();  // clear any default values
        //re-use previous stock values if exists
        if (isset($_GET['Stock'])) {
            $model->attributes = $_GET['Stock'];
        }

        $this->render('index', array(
            'model' => $model,
        ));
    }

    /**
     * Returns the data model based on the primary key given in the GET variable.
     * If the data model is not found, an HTTP exception will be raised.
     * @param integer the ID of the model to be loaded
     */
    public function loadModel($id) {
        $model = Stock::model()->findByPk($id);
        if ($model === null)
            throw new CHttpException(404, 'The requested page does not exist.');
        return $model;
    }

    /**
     * Performs the AJAX validation.
     * @param CModel the model to be validated
     */
    protected function performAjaxValidation($model) {
        if (isset($_POST['ajax']) && $_POST['ajax'] === 'stock-form') {
            echo CActiveForm::validate($model);
            Yii::app()->end();
        }
    }

    public function actionUpdateAjax() {
        if (isset($_REQUEST['dir'])) {
            $dir = $_REQUEST['dir'];
            if ($_SESSION['house'] == "HOSE")
                $sanChungKhoan = 1; else
            if ($_SESSION['house'] == "HNX")
                $sanChungKhoan = 2; else
            if ($_SESSION['house'] == "UPCOM")
                $sanChungKhoan = 4; else
                $sanChungKhoan = 1;

            $this->importToDb($dir, 'fpt', 'csv', $sanChungKhoan);
            echo 'NOt Done';
            exit;
        }

        //$this->renderPartial('_importFromFile',array('status'=>$status), false, true);
    }

    public function actionImportFromFile() {
        $form = new Stock;
        $dataProvider = '';
        $dir = '';
        if (!empty($_POST['Stock'])) {
            $form->file = CUploadedFile::getInstance($form, 'file');
            if ($form->file) {
                $dir = dirname(__FILE__) . '/../../upload/importfromfile/' . $form->file->name;
                $form->file->saveAs($dir);
                $rawData = $this->getDataReviewFile($dir, 'fpt', 'csv');
                // Create CArrayDataProvider from array
                $dataProvider = new CArrayDataProvider($rawData, array(
                            'id' => 'grid_fromFile',
                            'sort' => array('attributes' => array('id')),
                            'pagination' => array('pageSize' => 20), // Pagination won't work with CArrayDataProvider so we have big pageSize to make sure it displays all results
                        ));
            }
        }
        // params for rendering
        $params = array(
            'form' => $form,
            'dataProvider' => $dataProvider,
            'dir' => $dir
        );

        $this->render('importFromFile/index', $params);
    }

    /**
     * importToDb
     * Import generated data to db
     * @param string $file
     * @param string $source
     * @param string $type
     * @access private
     * @return void
     */
    private function importToDb($file, $source, $type, $sanChungKhoan) {
        //Stock::model()->saveStock('2011-11-11 00:00:00', 386, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5); 
        if (($handle = fopen($file, "r")) !== FALSE) {
            $row = 1;
            $result = array();
            $temp = ",";
            begin: while (($data = fgetcsv($handle, 1000, $temp)) !== FALSE) {
                $num = count($data);
                if (count($data) < 17) {
                    $temp = ";";
                    goto begin;
                    //break;
                }
                $rowData = array();
                //echo "<p> $num fields in line $row: <br /></p>\n";
                $row++;
                $check = 1;
                $model = new Stock();
                for ($c = 0; $c < $num; $c++) {
                    if ($data[0] == null || $data[0] == null || $data[1] == null || $data[1] == '' || is_numeric($data[2]) == false || is_numeric($data[3]) == false) {
                        $check = 0;
                        $c = $num;
                    }
                    switch ($c) {
                        case 0:
                            $pieces = explode("/", $data[$c]);
                            $model->timestamp = $pieces[2] . "-" . $pieces[1] . "-" . $pieces[0] . " 00:00:00";

                            break;
                        case 1:
                            // su ly ticket , neu chua co thi them moi.
                            $tempTicketID = $data[$c];
                            $StockObj = Company::model()->findByAttributes(array('ticket' => $tempTicketID));
                            if (is_null($StockObj)) {
                                Company::model()->saveCompany($tempTicketID);
                                $TempStockObj = Company::model()->findByAttributes(array('ticket' => $tempTicketID));
                                $model->companyID = $TempStockObj->id;
                            } else
                                $model->companyID = $StockObj->id;
                            break;
                        case 2:
                            $model->ref = floatval(Stock::model()->remoreString($data[$c]));
                            break;
                        case 3:
                            $model->ceiling = floatval(Stock::model()->remoreString($data[$c]));
                            break;
                        case 4:
                            $model->floor = floatval(Stock::model()->remoreString($data[$c]));
                            break;
                        case 5:
                            $model->open = floatval(Stock::model()->remoreString($data[$c]));
                            break;
                        case 6:
                            $model->close = floatval(Stock::model()->remoreString($data[$c]));
                            break;
                        case 7:
                            $model->high = floatval(Stock::model()->remoreString($data[$c]));
                            break;
                        case 8:
                            $model->low = floatval(Stock::model()->remoreString($data[$c]));
                            break;
                        case 9:
                            $model->avg = floatval(Stock::model()->remoreString($data[$c]));
                            break;
                        case 12:
                            $model->volumeKhopLenh = floatval(Stock::model()->remoreString($data[$c]));
                            break;
                        case 13:
                            $model->volumeAgreement = floatval(Stock::model()->remoreString($data[$c]));
                            break;
                        case 15:
                            $model->valueKhopLenh = floatval(Stock::model()->remoreString($data[$c]));
                            break;
                        case 16:
                            $model->valueAgreement = floatval(Stock::model()->remoreString($data[$c]));
                            break;
                    }
                }
                $duplication = Stock::model()->findByAttributes(array('timestamp' => $model->timestamp, 'companyID' => $model->companyID));
                if ($check == 1 && is_null($duplication))
                    Stock::model()->saveStock($model->timestamp, $model->companyID, $sanChungKhoan, $model->ref, $model->ceiling, $model->floor, $model->open, $model->close, $model->high, $model->low, $model->avg, $model->volumeKhopLenh, $model->volumeAgreement, $model->valueKhopLenh, $model->valueAgreement);
            }
            //print_r($result);
            return $result;
            fclose($handle);
        }
    }

    private function getDataReviewFile($file, $type) {
        $findEx = 0;
        $ExchenTem = "";
        $_SESSION['house'] = "HNX";
        if (($handle = fopen($file, "r")) !== FALSE) {
            $row = 1;
            $result = array();
            $temp = ",";
            begin: while (($data = fgetcsv($handle, 1000, $temp)) !== FALSE) {
                $num = count($data);
                if (count($data) < 17) {
                    $temp = ";";
                    goto begin;
                    //break;
                }
                $rowData = array();
                //echo "<p> $num fields in line $row: <br /></p>\n";
                $row++;
                $check = 1;
                for ($c = 0; $c < $num; $c++) {
                    if ($data[0] == null || $data[0] == null || $data[1] == null || $data[1] == '' || is_numeric($data[2]) == false || is_numeric($data[3]) == false) {
                        $check = 0;
                        $c = $num;
                    }
                    if ($c == 0)
                        $rowData['id'] = $row;
                    if ($c == 0)
                        $rowData['Date'] = $data[$c];
                    if ($c == 1) {
                        $ExchenTem = $data[$c];
                        $rowData['companyID'] = $data[$c];
                    }
                    if ($c == 2)
                        $rowData['TC'] = $data[$c];
                    if ($c == 3)
                        $rowData['ceiling'] = $data[$c];
                    if ($c == 4)
                        $rowData['floor'] = $data[$c];
                    if ($c == 5)
                        $rowData['open'] = $data[$c];
                    if ($c == 6)
                        $rowData['close'] = $data[$c];
                    if ($c == 7)
                        $rowData['high'] = $data[$c];
                    if ($c == 8)
                        $rowData['low'] = $data[$c];
                    if ($c == 9)
                        $rowData['avg'] = $data[$c];
                    if ($c == 10)
                        $rowData['plus'] = $data[$c];
                    if ($c == 11)
                        $rowData['minus'] = $data[$c];
                    if ($c == 12)
                        $rowData['volumeKhopLenh'] = $data[$c];
                    if ($c == 13)
                        $rowData['volumeAgreement'] = $data[$c];
                    if ($c == 14)
                        $rowData['volumeTotal'] = $data[$c];
                    if ($c == 15)
                        $rowData['valueKhopLenh'] = $data[$c];
                    if ($c == 16)
                        $rowData['valueAgreement'] = $data[$c];
                    if ($c == 17)
                        $rowData['valueTotal'] = $data[$c];
                }

                if ($check == 1) {
                    if ($findEx == 0) {
                        $_SESSION['house'] = Stock::model()->findStockID($data[1]);
                        $findEx = 1;
                    }
                    array_push($result, $rowData);
                }
            }
            //print_r($result);
            return $result;
            fclose($handle);
        }
    }

    public function actionImportFromWeb() {
        $model = new Stock;

        // Uncomment the following line if AJAX validation is needed
        // $this->performAjaxValidation($model);

        $isSubmitting = isset($_POST['Stock']);
        if (!$isSubmitting) { //1st-opened, then just display the view
            $this->render('importFromWeb/index', array(
                'model' => $model,
            ));
        } elseif ($isSubmitting) { //submitting -> save the stocks and view the result
            $model->attributes = $_POST['Stock'];
            if ($model->save()) {
                $this->redirect(array('view', 'id' => $model->id));
            }
        }
    }

    public function actionSLR() {
        $model = new Stock;

        // Uncomment the following line if AJAX validation is needed
        // $this->performAjaxValidation($model);

        $isSubmitting = isset($_POST['Stock']);
        if (!$isSubmitting) { //1st-opened, then just display the view
            $this->render('report/SLR/index', array(
                'model' => $model,
            ));
        } elseif ($isSubmitting) { //submitting -> save the stocks and view the result
            $model->attributes = $_POST['Stock'];
            if ($model->save()) {
                $this->redirect(array('view', 'id' => $model->id));
            }
        }
    }

    public function actionValidation() {
        $model = new Stock('searchForValidation');
        $from = $to = '';
        $model->unsetAttributes();  // clear any default values
        if (isset($_GET['Stock'])) {
            $model->attributes = $_GET['Stock'];
            $from = $_GET['from'];
            $to = $_GET['to'];
        }

        //Get a list of data
        if (isset(Yii::app()->request->cookies['isValidating']) && Yii::app()->request->cookies['isValidating']->value == 1) {
            $dataProvider = $model->searchForValidation($from, $to, null, true);
        } else {
            $dataProvider = $model->searchForValidation($from, $to);
        }

        //Starting data in $_COOKIE to use for validate
        $data = array(); //create new array to store metadata used for determine which column is wrong
        $i = 0;
        foreach ($dataProvider->getData() as $row) {
            $data[$i] = Stock::validateData($row);
            ++$i;
        }
        Yii::app()->user->setState('data', json_encode($data)); //Store the data in $_SESSION

        $this->render('validation', array(
            'model' => $model,
            'dataProvider' => $dataProvider,
        ));
    }

    public function actionPreviewImportFromWeb() {
        echo "hello";
    }

    //Function for add new Stock by inline-editor
    public function actionAddStock() {
        //Create new model
        $model = new Stock;

        //Now, get all the params from the $POST to the model
        //If there're some params have the 'null' value => we set it 0
        if (isset($_POST['Stock'])) {
            $model->attributes = $_POST['Stock'];
            $model->timestamp = Stock::uk_date_to_mysql_date($model->timestamp);
            /////////////
            if ($model->open == null)
                $model->open = 0;
            if ($model->close == null)
                $model->close = 0;
            if ($model->high == null)
                $model->high = 0;
            if ($model->low == null)
                $model->low = 0;
            if ($model->ref == null)
                $model->ref = 0;
            if ($model->avg == null)
                $model->avg = 0;
            if ($model->ceiling == null)
                $model->ceiling = 0;
            if ($model->floor == null)
                $model->floor = 0;
            if ($model->volumeKhopLenh == null)
                $model->volumeKhopLenh = 0;
            if ($model->volumeAgreement == null)
                $model->volumeAgreement = 0;
            if ($model->valueKhopLenh == null)
                $model->valueKhopLenh = 0;
            if ($model->valueAgreement == null)
                $model->valueAgreement = 0;
            ////////////
            //Then save the model to database
            if ($model->save()) {
                //if saved, return the result to the view
                $com = Company::model()->findByPk($model->companyID);
                $ex = Exchanges::model()->findByPk($model->exchangeID);
                $model = Stock::model()->findByPk($model->id);
                $text = '<tr class="added">
                    <td>' . $com->ticket . '</td>
                    <td>' . $ex->name . '</td>
                    <td>' . date('d/m/Y', strtotime($model->timestamp)) . '</td>
                    <td>' . $model->open . '</td>
                    <td>' . $model->close . '</td>
                    <td>' . $model->high . '</td>
                    <td>' . $model->low . '</td>
                    <td>' . $model->ref . '</td>
                    <td>' . $model->avg . '</td>
                    <td>' . $model->ceiling . '</td>
                    <td>' . $model->floor . '</td>
                    <td>' . $model->volumeKhopLenh . '</td>
                    <td>' . $model->volumeAgreement . '</td>
                    <td>' . $model->valueKhopLenh . '</td>
                    <td>' . $model->valueAgreement . '</td>
                    <td class="button-column">
                    </td>
                    </tr>';
                echo $text;
            }
        }
    }

    public function actionEdit() {
        if (Yii::app()->request->isAjaxRequest) { //check if the request is ajaxRequest
            //Create new model and get all params to the model
            $model = new Stock;
            $model->companyID = $_POST['companyid'];
            $model->exchangeID = $_POST['exchangeid'];
            $model->timestamp = Stock::uk_date_to_mysql_date($_POST['timestamp']); //date('Y-m-d H:i:s', strtotime($_POST['timestamp']));
            $model->open = $_POST['open'];
            $model->close = $_POST['close'];
            $model->low = $_POST['low'];
            $model->high = $_POST['high'];
            $model->ref = $_POST['ref'];
            $model->avg = $_POST['avg'];
            $model->ceiling = $_POST['ceiling'];
            $model->floor = $_POST['floor'];
            $model->volumeKhopLenh = $_POST['volumeKhopLenh'];
            $model->volumeAgreement = $_POST['volumeAgreement'];
            $model->valueKhopLenh = $_POST['valueKhopLenh'];
            $model->valueAgreement = $_POST['valueAgreement'];
            $model->id = $_POST['id'];

            //Just like actionAdd, if there're some null value, set it )
            /////////////
            if ($model->open == null)
                $model->open = 0;
            if ($model->close == null)
                $model->close = 0;
            if ($model->high == null)
                $model->high = 0;
            if ($model->low == null)
                $model->low = 0;
            if ($model->ref == null)
                $model->ref = 0;
            if ($model->avg == null)
                $model->avg = 0;
            if ($model->ceiling == null)
                $model->ceiling = 0;
            if ($model->floor == null)
                $model->floor = 0;
            if ($model->volumeKhopLenh == null)
                $model->volumeKhopLenh = 0;
            if ($model->volumeAgreement == null)
                $model->volumeAgreement = 0;
            if ($model->valueKhopLenh == null)
                $model->valueKhopLenh = 0;
            if ($model->valueAgreement == null)
                $model->valueAgreement = 0;
            ////////////
            //Update to database
            $result = Stock::model()->updateByPk($model->id, array(
                'companyID' => $model->companyID,
                'exchange' => $model->exchangeID,
                'timestamp' => $model->timestamp,
                'open' => $model->open,
                'low' => $model->low,
                'high' => $model->high,
                'close' => $model->close,
                'ref' => $model->ref,
                'avg' => $model->avg,
                'ceiling' => $model->ceiling,
                'floor' => $model->floor,
                'volumeKhopLenh' => $model->volumeKhopLenh,
                'volumeAgreement' => $model->volumeAgreement,
                'valueKhopLenh' => $model->valueKhopLenh,
                'valueAgreement' => $model->valueAgreement,
                    ));
            //return the result
            //This result is the number of rows have been changed in DB
            //We used UpdateByPk function => only one row has been changed at a time
            //So, if result is 1 => we succeeded
            //If 0 => we failed
            echo $result;
        }
    }

    public function actionDataValidate() {
        if (Yii::app()->request->isAjaxRequest) {
            echo Yii::app()->user->getState('data');
        }
    }

    //---- Stock Report -----------------------------------------------------------------------------------------------------
    public function actionReport() {
        $this->render('report');
    }

    public function actionFormula() {
        $this->render('report/formula/index');
    }

    public function actionChart() {
        $this->render('report/chart/index');
    }

    //This action's used for update Chart image in ChartView
    public function actionGetChart() {
        global $timeStamps, $volData, $highData, $lowData, $openData, $closeData,
        $compareData, $resolution;

        // In this demo, we just assume we plot up to the latest time. So end date is now.
        $endDate = chartTime2(time());

        // If the trading day has not yet started (before 9:30am), or if the end date is
        // on on Sat or Sun, we set the end date to 4:00pm of the last trading day
        while ((fmod2($endDate, 86400) < 9 * 3600 + 30 * 60) || (getChartWeekDay($endDate
        ) == 0) || (getChartWeekDay($endDate) == 6)) {
            $endDate = $endDate - fmod2($endDate, 86400) - 86400 + 16 * 3600;
        }
        // The data series we want to get.
        $tickerKey = trim($_REQUEST["TickerSymbol"]);

        // The duration selected by the user
        $durationInDays = (int) ($_REQUEST["TimeRange"]);
        if ($durationInDays == 0) { //If TimeRange == 0, we'll get all rows in db
            //Get the oldest row in DB => the most earliest date
            $oldestRecord = Stock::model()->findAll(array("order" => "timestamp asc", "limit" => "1", "condition" => "companyID = " . $tickerKey));
            $now = Date("Y-m-d h:i:s"); //Get the time for now
            $durationInDays = (int) ((strtotime($now) - strtotime($oldestRecord[0]->timestamp)) / 86400 + 1); //Calculate that we between the oldest date and now
            //we have how many days
        }

        // Compute the start date by subtracting the duration from the end date.
        $startDate = $endDate;
        if ($durationInDays >= 30) {
            // More or equal to 30 days - so we use months as the unit
            $YMD = getChartYMD($endDate);
            $startMonth = (int) ($YMD / 100) % 100 - (int) (($durationInDays / 30) % 12);
            if ($startMonth == 0) {
                $startMonth = 12;
            }

            $startYear = (int) ($YMD / 10000) - (int) (($durationInDays / 30) / 12);
            while ($startMonth < 1) {
                $startYear = $startYear - 1;
                $startMonth = $startMonth + 12;
            }
            $startDate = chartTime($startYear, $startMonth, 1);
        } else {
            // Less than 30 days - use day as the unit. The starting point of the axis is
            // always at the start of the day (9:30am). Note that we use trading days, so
            // we skip Sat and Sun in counting the days.
            $startDate = $endDate - fmod2($endDate, 86400) + 9 * 3600 + 30 * 60;
            for ($i = 0; $i < $durationInDays; ++$i) {
                if (getChartWeekDay($startDate) == 1) {
                    $startDate = $startDate - 3 * 86400;
                } else {
                    $startDate = $startDate - 86400;
                }
            }
        }

        // The moving average periods selected by the user.
        $avgPeriod1 = 0;
        $avgPeriod1 = (int) ($_REQUEST["movAvg1"]);
        $avgPeriod2 = 0;
        $avgPeriod2 = (int) ($_REQUEST["movAvg2"]);

        if ($avgPeriod1 < 0) {
            $avgPeriod1 = 0;
        } else if ($avgPeriod1 > 300) {
            $avgPeriod1 = 300;
        }

        if ($avgPeriod2 < 0) {
            $avgPeriod2 = 0;
        } else if ($avgPeriod2 > 300) {
            $avgPeriod2 = 300;
        }

        // We need extra leading data points in order to compute moving averages.
        $extraPoints = 20;
        if ($avgPeriod1 > $extraPoints) {
            $extraPoints = $avgPeriod1;
        }
        if ($avgPeriod2 > $extraPoints) {
            $extraPoints = $avgPeriod2;
        }

        // Get the data series to compare with, if any.
        $compareKey = trim($_REQUEST["CompareWith"]);
        $compareData = null;
        if (getData($compareKey, $startDate, $endDate, $durationInDays, $extraPoints)) {
            $compareData = $closeData;
        }

        //Get data using Ticker key
        if (!getData($tickerKey, $startDate, $endDate, $durationInDays, $extraPoints)) {
            return errMsg("Please enter a valid ticker symbol");
        }

        // We now confirm the actual number of extra points (data points that are before
        // the start date) as inferred using actual data from the database.
        $extraPoints = count($timeStamps);
        for ($i = 0; $i < count($timeStamps); ++$i) {
            if ($timeStamps[$i] >= $startDate) {
                $extraPoints = $i;
                break;
            }
        }

        // Check if we have no data
        if (count($timeStamps) == 0) {
            // No data - just display the no data message.
            return errMsg("No data available for the specified time period");
        }

        // Check if there is any valid data
        if ($extraPoints >= count($timeStamps)) {
            // No data - just display the no data message.
            return errMsg("No data available for the specified time period");
        }

        // In some finance chart presentation style, even if the data for the latest day
        // is not fully available, the axis for the entire day will still be drawn, where
        // no data will appear near the end of the axis.
        if ($resolution < 86400) {
            // Add extra points to the axis until it reaches the end of the day. The end
            // of day is assumed to be 16:00 (it depends on the stock exchange).
            $lastTime = $timeStamps[count($timeStamps) - 1];
            $extraTrailingPoints = (int) ((16 * 3600 - fmod2($lastTime, 86400)) /
                    $resolution);
            for ($i = 0; $i < $extraTrailingPoints; ++$i) {
                $timeStamps[] = $lastTime + $resolution * ($i + 1);
            }
        }

        //
        // At this stage, all data are available. We can draw the chart as according to
        // user input.
        //

    //
    // Determine the chart size. In this demo, user can select 4 different chart
        // sizes. Default is the large chart size.
        //
        $width = 780;
        $mainHeight = 255;
        $indicatorHeight = 80;

        $size = $_REQUEST["ChartSize"];
        if ($size == "S") {
            // Small chart size
            $width = 450;
            $mainHeight = 160;
            $indicatorHeight = 60;
        } else if ($size == "M") {
            // Medium chart size
            $width = 620;
            $mainHeight = 215;
            $indicatorHeight = 70;
        } else if ($size == "H") {
            // Huge chart size
            $width = 970;
            $mainHeight = 320;
            $indicatorHeight = 90;
        }

        // Create the chart object using the selected size
        $m = new FinanceChart($width);
        $m->setBackground(0x000000);
        // Set the data into the chart object
        $m->setData($timeStamps, $highData, $lowData, $openData, $closeData, $volData, $extraPoints);

        //
        // We configure the title of the chart. In this demo chart design, we put the
        // company name as the top line of the title with left alignment.
        //
        $companyName = Company::model()->findByPk($tickerKey)->ticket;
        $m->addPlotAreaTitle(TopLeft, $companyName);
        $m->m_xAxisFontColor = 0xFFFFFF;
        $m->m_yAxisFontColor = 0xFFFFFF;
        
        // We displays the current date as well as the data resolution on the next line.
        $resolutionText = "";
        if ($resolution == 30 * 86400) {
            $resolutionText = "Monthly";
        } else if ($resolution == 7 * 86400) {
            $resolutionText = "Weekly";
        } else if ($resolution == 86400) {
            $resolutionText = "Daily";
        }

        $m->addPlotAreaTitle(BottomLeft, sprintf(
                        "<*font=arial.ttf,size=10*>%s - %s chart", $m->formatValue(chartTime2(time()), "dd/mm/yyyy"), $resolutionText));

        // A copyright message at the bottom left corner the title area
        $m->addPlotAreaTitle(BottomRight, "<*font=arial.ttf,size=8*>(c) Advanced Software Engineering");
        $m->setPlotAreaStyle(0x000000, 0x333333, 0x333333, 0xFFFFFF, 0x333333);
        $m->setLegendStyle("arial.ttf", 8, 0xffffff, 0x6A93D4);
        //
        // Add the first techical indicator according. In this demo, we draw the first
        // indicator on top of the main chart.
        //
        $a = addIndicator($m, $_REQUEST["Indicator1"], $indicatorHeight);


        // Add the main chart
        $a = $m->addMainChart($mainHeight);
        // Set log or linear scale according to user preference
        if (isset($_REQUEST["LogScale"]) && $_REQUEST["LogScale"] == "on") {
            $m->setLogScale(true);
        }

        // Set axis labels to show data values or percentage change to user preference
        if (isset($_REQUEST["PercentageScale"]) && $_REQUEST["PercentageScale"] == "on") {
            $m->setPercentageAxis();
        }

        // Draw any price line the user has selected
        $mainType = $_REQUEST["ChartType"];
        if ($mainType == "Close") {
            $close = $m->addCloseLine(0xFF6700);
            $close->setHTMLImageMap("", "", "title='[{xLabel|dd/mm/yyyy}] Closing Price: {value}' class='mainChart' onclick='draw({x}, {value});'");
        } else if ($mainType == "TP") {
            $m->addTypicalPrice(0xFF6700);
        } else if ($mainType == "WC") {
            $wc = $m->addWeightedClose(0xFF6700);
            $wc->setHTMLImageMap("", "", "title='[{xLabel|dd/mm/yyyy}] Weighted Close: {value}' class='mainChart'");
        } else if ($mainType == "Median") {
            $median = $m->addMedianPrice(0xFF6700);
            $median->setHTMLImageMap("", "", "title='[{xLabel|dd/mm/yyyy}] Median Price: {value}' class='mainChart'");
        }

        // Add comparison line if there is data for comparison
        if ($compareData != null) {
            if (count($compareData) > $extraPoints) {
                $m->addComparison($compareData, 0x0000ff, $compareKey);
            }
        }

        // Add moving average lines.
        $sma1 = addMovingAvg($m, $_REQUEST["avgType1"], $avgPeriod1, 0xffdd00);
        $sma1->setHTMLImageMap("", "", "title='[{xLabel|dd/mm/yyyy}] SMA(" . $avgPeriod1 . "): {value}'");
        $sma2 = addMovingAvg($m, $_REQUEST["avgType2"], $avgPeriod2, 0x9900ff);
        $sma2->setHTMLImageMap("", "", "title='[{xLabel|dd/mm/yyyy}] SMA(" . $avgPeriod2 . "): {value}'");

        //
        // Draw candlesticks or OHLC symbols if the user has selected them.
        //
        if ($mainType == "CandleStick") {
            $chart = $m->addCandleStick(0x33ff33, 0xff3333);
            $chart->getDataSet(1)->setDataColor(0xff3333, 0xffffff);
            $chart->getDataSet(0)->setDataColor(0x33ff33, 0x777777);
            
            $chart->setHTMLImageMap("", "", "title='[{xLabel|dd/mm/yyyy}] Open: {open}; Close: {close}; High: {high}; Low: {low}' class='mainChart' onclick='draw({x}, {close});'");
        } else if ($mainType == "OHLC") {
            $chart = $m->addHLOC(0x008800, 0xcc0000);
            $chart->setHTMLImageMap("", "", "title='[{xLabel|dd/mm/yyyy}] Open: {open}; Close: {close}; High: {high}; Low: {open}' class='mainChart' onclick='draw({x}, {close});'");
        }

        // Add parabolic SAR if necessary
        if (isset($_REQUEST["ParabolicSAR"]) && $_REQUEST["ParabolicSAR"] == 'on') {
            $psar = $m->addParabolicSAR(0.02, 0.02, 0.2, DiamondShape, 2, 0x008800, 0xdddddd);
            $psar->setHTMLImageMap("", "", "title='[{xLabel|dd/mm/yyyy}] Parabolic SAR: {value}'");
        }

        // Add price band/channel/envelop to the chart according to user selection
        $bandType = $_REQUEST["Band"];
        if ($bandType == "BB") {
            $bollinger = $m->addBollingerBand(20, 2, 0x006A93D4, 0xFF000000);
        } else if ($bandType == "DC") {
            $m->addDonchianChannel(20, 0x9999ff, 0xc06666ff);
        } else if ($bandType == "Envelop") {
            $m->addEnvelop(20, 0.1, 0x9999ff, 0xc06666ff);
        }

        // Add volume bars to the main chart if necessary
        if (isset($_REQUEST["Volume"]) && $_REQUEST["Volume"] == "on") {
            $temp = $m->addVolBars($indicatorHeight, 0x99ff99, 0xff9999, 0xc0c0c0);
            $temp->setHTMLImageMap("", "", "title='[{xLabel|dd/mm/yyyy}] Vol: {value}'");
        }

        // Add additional indicators as according to user selection.
        addIndicator($m, $_REQUEST["Indicator2"], $indicatorHeight);
        addIndicator($m, $_REQUEST["Indicator3"], $indicatorHeight);
        addIndicator($m, $_REQUEST["Indicator4"], $indicatorHeight);

        $indicatorCount = 0;
        for ($i = 1; $i < 5; ++$i) {
            if ($_REQUEST["Indicator" . $i] != "None") {
                ++$indicatorCount;
            }
        }

        //Get parameter for the base line
        if (isset($_REQUEST['lineX1']) && isset($_REQUEST['lineY1']) && isset($_REQUEST['lineX2']) && isset($_REQUEST['lineY2'])) {
            $x1Val = floatval($_REQUEST['lineX1']);
            $y1Val = floatval($_REQUEST['lineY1']);
            $x2Val = floatval($_REQUEST['lineX2']);
            $y2Val = floatval($_REQUEST['lineY2']);
            $m->layout();
            $x1Coor = $a->getXCoor($x1Val);
            $y1Coor = $a->getYCoor($y1Val);
            $x2Coor = $a->getXCoor($x2Val);
            $y2Coor = $a->getYCoor($y2Val);

            $left = $m->m_leftMargin;
            $right = $width - $m->m_rightMargin;
            $distance = $y2Coor - $y1Coor;
            $minYCoorVal = $y1Coor;

            //Draw Fibonacci lines
            for ($i = 0; $i < 9; ++$i) {
                if (isset($_REQUEST['fibo' . $i])) {
                    $p = floatval($_REQUEST['fibo' . $i]) / 100;
                    $fiboY = $minYCoorVal + $distance * $p;
                    $a->addLine($left, $fiboY, $right, $fiboY, 0xFF3333);
                }
            }
            //Draw base line
            $a->addLine($x1Coor, $y1Coor, $x2Coor, $y2Coor, 0xFF3333);
        }

        // Output the chart
        $imageCode = $m->makeChart2(PNG);
        $imageCode = base64_encode($imageCode);
        $imageMap = $m->getHTMLImageMap("clickline.php", "", "title='[{xLabel|dd/mm/yyyy}] <em>{value}<em>'");

        //Get all the data and convert to JSON
        $data = array('imageCode' => $imageCode, 'imageMap' => $imageMap);

        echo json_encode($data);
    }

    //---------------------------------------------------------------------------------------------------------
}